package knowledgebase.dao;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import knowledgebase.model.*;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;

/**
 *
 * @author eugene
 */
@Repository("PermissionDAO")
public class PermissionDAO {
    
    HibernateTemplate hibernateTemplate;
    
    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        hibernateTemplate = new HibernateTemplate(sessionFactory);
    }
    
    public Long saveUserDocumentBlockAccess(UserDocumentBlockAccess userDocumentBlockAccess) {
        List<UserDocumentBlockAccess> userDocumentBlocksAccess = hibernateTemplate.findByNamedParam("from UserDocumentBlockAccess where block.id = :blockId and accessType = :accessType", new String[]{"blockId", "accessType"}, new Object[]{userDocumentBlockAccess.getBlock().getId(), userDocumentBlockAccess.getAccessType()});
        if(userDocumentBlocksAccess.isEmpty()) {
            return (Long) hibernateTemplate.save(userDocumentBlockAccess);
        }
        return userDocumentBlocksAccess.get(0).getId();
    }
    
    public Long saveUserBlockAccess(UserBlockAccess userBlockAccess) {
        List<UserBlockAccess> userBlocksAccess = hibernateTemplate.findByNamedParam("from UserBlockAccess where user = :user and blockAccess.block.id = :blockId and blockAccess.accessType = :accessType", new String[]{"user", "blockId", "accessType"}, new Object[]{userBlockAccess.getUser(), userBlockAccess.getBlockAccess().getBlock().getId(), userBlockAccess.getBlockAccess().getAccessType()});
        if(userBlocksAccess.isEmpty()) {
            return (Long) hibernateTemplate.save(userBlockAccess);
        } else {
            userBlockAccess.setId(userBlocksAccess.get(0).getId());
            hibernateTemplate.update(userBlockAccess);
        }
        return userBlocksAccess.get(0).getId();
    }
    
    public List<DocumentBlock> getDocumentBlocksForUser(User user, Document document, AccessType accessType) {
        StringBuilder query = new StringBuilder("select block ");
        query.append("from UserBlockAccess uba join uba.blockAccess udba ");
        query.append("join udba.block block ");
        query.append("where block.parentDocument = :parentDocument and uba.user = :user and udba.accessType = :accessType");
        List<DocumentBlock> documentBlocks = hibernateTemplate.findByNamedParam(query.toString(), new String[] {"parentDocument", "user", "accessType"}, new Object[] {document, user, accessType});
        return documentBlocks;
    }
    
    public List<AccessType> getGlobalRolePermissions(Role role) {
        return hibernateTemplate.findByNamedParam("select p.accessType from RoleGlobalPermission p  where p.role = :role", "role", role);
    }
    
    public void removeAccessToBlockForUser(User user, DocumentBlock block, AccessType accessType) {
        StringBuilder query = new StringBuilder("select uba from UserBlockAccess uba join uba.blockAccess udba ");
        query.append("where uba.user = :user and udba.block = :block and udba.accessType = :accessType");
        List<UserBlockAccess> userBlockAccessList = hibernateTemplate.findByNamedParam(query.toString(), new String[] {"user", "block", "accessType"}, new Object[] {user, block, accessType});
        if(!userBlockAccessList.isEmpty()) {
            hibernateTemplate.deleteAll(userBlockAccessList);
        }
    }
    
    public Long saveRoleDocumentBlockAccess(RoleDocumentBlockAccess roleDocumentBlockAccess) {
        List<RoleDocumentBlockAccess> roleDocumentBlocksAccess = hibernateTemplate.findByNamedParam("from RoleDocumentBlockAccess where block.id = :blockId and accessType = :accessType", new String[]{"blockId", "accessType"}, new Object[]{roleDocumentBlockAccess.getBlock().getId(), roleDocumentBlockAccess.getAccessType()});
        if(roleDocumentBlocksAccess.isEmpty()) {
            return (Long) hibernateTemplate.save(roleDocumentBlockAccess);
        }
        return roleDocumentBlocksAccess.get(0).getId();
    }
    
    public Long saveRoleBlockAccess(RoleBlockAccess roleBlockAccess) {
        List<RoleBlockAccess> roleBlocksAccess = hibernateTemplate.findByNamedParam("from RoleBlockAccess where role = :role and blockAccess.block.id = :blockId and blockAccess.accessType = :accessType", new String[]{"role", "blockId", "accessType"}, new Object[]{roleBlockAccess.getRole(), roleBlockAccess.getBlockAccess().getBlock().getId(), roleBlockAccess.getBlockAccess().getAccessType()});
        if(roleBlocksAccess.isEmpty()) {
            return (Long) hibernateTemplate.save(roleBlockAccess);
        } else {
            roleBlockAccess.setId(roleBlocksAccess.get(0).getId());
            hibernateTemplate.update(roleBlockAccess);
        }
        return roleBlocksAccess.get(0).getId();
    }
    
    public List<DocumentBlock> getDocumentBlocksForRole(Role role, Document document, AccessType accessType) {
        StringBuilder query = new StringBuilder("select block ");
        query.append("from RoleBlockAccess rba join rba.blockAccess rdba ");
        query.append("join rdba.block block ");
        query.append("where block.parentDocument = :parentDocument and rba.role = :role and rdba.accessType = :accessType");
        return hibernateTemplate.findByNamedParam(query.toString(), new String[] {"parentDocument", "role", "accessType"}, new Object[] {document, role, accessType});
    }
    
    public void removeAccessToBlockForRole(Role role, DocumentBlock block, AccessType accessType) {
        StringBuilder query = new StringBuilder("select rba from RoleBlockAccess rba join rba.blockAccess rdba ");
        query.append("where rba.role = :role and rdba.block = :block and rdba.accessType = :accessType");
        List<RoleBlockAccess> roleBlockAccessList = hibernateTemplate.findByNamedParam(query.toString(), new String[] {"role", "block", "accessType"}, new Object[] {role, block, accessType});
        if(!roleBlockAccessList.isEmpty()) {
            hibernateTemplate.deleteAll(roleBlockAccessList);
        }
    }
    
    public List<RoleGlobalPermission> getAllRowGlobalPermissions() {
        return (List<RoleGlobalPermission>) hibernateTemplate.find("from RoleGlobalPermission");
    }
    
    public Long saveRoleGlobalAccess(RoleGlobalPermission rgp){
        List<RoleGlobalPermission> list = findRoleGlobalPermissionRecords(rgp);
        if(list.isEmpty()){
            return (Long) hibernateTemplate.save(rgp);
        } else {
            return list.get(0).getId();
        }
    }
    
    public void removeRoleGlobalAccess(RoleGlobalPermission rgp){
        List<RoleGlobalPermission> list = findRoleGlobalPermissionRecords(rgp);
        if(!list.isEmpty()) {
            hibernateTemplate.deleteAll(list);
        }
    }
    
    private List<RoleGlobalPermission> findRoleGlobalPermissionRecords(RoleGlobalPermission rgp){
        StringBuilder query = new StringBuilder("select rgp from RoleGlobalPermission rgp ");
        query.append("where rgp.role = :role and rgp.accessType = :accessType");
        return hibernateTemplate.findByNamedParam(query.toString(), new String[] {"role", "accessType"}, new Object[] {rgp.getRole(), rgp.getAccessType()});
    }
    
    public void removeAllRoleGlobalPermissions(Long roleId){
        
        Role role = new Role();
        role.setId(roleId);
        RoleGlobalPermission rgp = new RoleGlobalPermission();
        rgp.setRole(role);
        
        AccessType accessType = new AccessType(1, "Create block");
        rgp.setAccessType(accessType);
        removeRoleGlobalAccess(rgp);
        
        accessType = new AccessType(2, "Update block");
        rgp.setAccessType(accessType);
        removeRoleGlobalAccess(rgp);
        
        accessType = new AccessType(3, "Read block");
        rgp.setAccessType(accessType);
        removeRoleGlobalAccess(rgp);
        
        accessType = new AccessType(4, "Delete block");
        rgp.setAccessType(accessType);
        removeRoleGlobalAccess(rgp);
    }
}
